package com.sz.biz.logistics.base.service.impl;

import com.sz.biz.common.constants.ErrorCodes;
import com.sz.biz.common.constants.ModuleNames;
import com.sz.biz.logistics.base.entity.WeightSchema;
import com.sz.biz.logistics.base.entity.WeightSection;
import com.sz.biz.logistics.base.service.WeightSchemaService;
import com.sz.biz.logistics.base.dto.WeightSchemaDto;
import com.sz.biz.logistics.core.service.QuotationService;
import com.sz.common.base.cache.EntityCache;
import com.sz.common.base.constants.UserActions;
import com.sz.common.base.dao.ParamData;
import com.sz.common.base.dto.QResultDto;
import com.sz.common.base.dto.QueryParams;
import com.sz.common.base.exception.Exceptions;
import com.sz.common.base.service.AbstractService;
import com.sz.common.base.utils.EntityUtils;
import com.sz.common.core.service.PrincipalLogUtils;
import com.sz.common.core.service.PrincipalUtils;
import org.apache.commons.collections.map.HashedMap;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.*;

/**
 * Function: 计重 <br>
 * Author: xutao <br>
 * Date: 2017-2-17 15:04:00
 */
@Service
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public class WeightSchemaServiceImpl extends AbstractService implements WeightSchemaService {
    @Autowired
    QuotationService quotationService;
    @Override
    public void refreshCache() {
        EntityCache.clearNamespace(getMapperNamespace());
    }

    @Override
    public int addWeightSection(WeightSchemaDto weightSchemaDto) {

        WeightSchema weightSchema = new WeightSchema();
        BeanUtils.copyProperties(weightSchemaDto, weightSchema);

        if (isExistedWeightSchema(weightSchema)) {
            throw Exceptions.bizException(ErrorCodes.ERROR_BIZ_WEIGHT_SCHEMA_KEY_EXIST);
        }

        Collections.sort(weightSchemaDto.getWeightSectionList());

        //检查数据区间是否存在覆盖
        for (int i = 0; i < weightSchemaDto.getWeightSectionList().size() - 1; i++) {

            if (weightSchemaDto.getWeightSectionList().get(i).getEndPoint().doubleValue()
                    > weightSchemaDto.getWeightSectionList().get(i + 1).getStartPoint().doubleValue()) {

                //输出覆盖异常
                throw Exceptions.bizException(ErrorCodes.ERROR_BIZ_WEIGHT_SCHEMA_SECTION_OVERLAP);
            }
        }

        boolean isValadate = checkDataValidate(weightSchemaDto.getWeightSectionList());

        //检查数据的有效性，开始重量不能大于或等于结束重量
        if (!isValadate) {
            throw Exceptions.bizException(ErrorCodes.ERROR_BIZ_WEIGHT_SCHEMA_SECTION_DATA_ERROR);
        }

        if (weightSchema.getId() == null || weightSchema.getId() < 1) {

            weightSchema.setUid(generateNewUid());
            weightSchemaDto.setCreateTime(dao.getDbDate());
        }

        weightSchema.setActiveTime(dao.getDbDate());
        weightSchema.setIsActive(true);
        weightSchema.setCreator(PrincipalUtils.getAccountName());
        weightSchema.setCreatorId(PrincipalUtils.getAccountId());
        weightSchema.setId(null);
        dao.save(getSqlName("insertSelective"), weightSchema);
        weightSchemaDto.setUid(weightSchema.getUid());
        //对子表中的refId统一赋值
        for (int i = 0; i < weightSchemaDto.getWeightSectionList().size(); i++) {
            weightSchemaDto.getWeightSectionList().get(i).setRefId(weightSchema.getId());
        }

        List<WeightSection> weightSectionList = weightSchemaDto.getWeightSectionList();
        dao.batchInsert("WeightSectionMapper.insert", weightSectionList);

        //保存操作日志
        Map<String, Object> dataBackup = new HashMap<>();
        dataBackup.put("ADD_WEIGHT_SCHEMA", weightSchema);
        dataBackup.put("ADD_WEIGHT_SECTION_SCHEMA", weightSectionList);
        PrincipalLogUtils.addOperationLog(ModuleNames.BIZ, ModuleNames.BIZ_WEIGHT_SCHEMA, UserActions.ADD, "添加计重方案", dataBackup);

        return weightSchema.getId();
    }

    @Override
    public int updateWeightSection(WeightSchemaDto weightSchemaDto) {

        int result = 0;

        WeightSchema queryres = findById(weightSchemaDto.getId());

        if (queryres != null) {
            Timestamp dbTime = dao.getDbDate();

            //判断重量段方案是否有引用 hpeng.wang
            boolean isRef = quotationService.isWeightSchemaReferenced(queryres.getUid(),true);
            if (isRef) {
                throw Exceptions.bizException(ErrorCodes.ERROR_BIZ_WEIGHT_SCHEMA_REF, queryres.getUid());
            }

            Map<String, Object> dataBackup = new HashMap<>();
            dataBackup.put("UPDATE_WEIGHT", queryres);
            PrincipalLogUtils.addOperationLog(ModuleNames.BIZ, ModuleNames.BIZ_WEIGHT_SCHEMA, UserActions.UPDATE, "修改计重方案", dataBackup);

            WeightSchema weightSchema = new WeightSchema();
            BeanUtils.copyProperties(queryres, weightSchema);
            weightSchema.setIsActive(false);
            weightSchema.setInactiveTime(dbTime);
            dao.update(getSqlName("updateByPrimaryKeySelective"), weightSchema);

            weightSchemaDto.setUid(queryres.getUid());
            weightSchemaDto.setCreateTime(queryres.getCreateTime());
            result = addWeightSection(weightSchemaDto);
        }

        return result;
    }

    @Override
    public void deleteWeightSection(List<Integer> listId) {
        if (listId != null && listId.size() > 0) {
            List<WeightSchema> list = findByIds(listId);
            if (list.size() > 0) {
                //判断重量段方案是否有引用 hpeng.wang
                list.forEach(weightSchema -> {
                    boolean isRef = quotationService.isWeightSchemaReferenced(weightSchema.getUid(),false);
                    if (isRef) {
                        throw Exceptions.bizException(ErrorCodes.ERROR_BIZ_WEIGHT_SCHEMA_REF, weightSchema.getUid());
                    }
                });


                //备份数据
                Map<String, Object> dataBackup = new HashMap<>();
                dataBackup.put("BATCH_DELETE_WEIGHT", list);
                PrincipalLogUtils.addOperationLog(ModuleNames.BIZ, ModuleNames.BIZ_WEIGHT_SCHEMA, UserActions.DELETE, "删除计重方案", dataBackup);

                //更新要删除的数据状态
                Timestamp date = dao.getDbDate();//获取数据库时间
                List<ParamData> paramDataList = new ArrayList<>();

                for (int id : listId) {
                    ParamData paramData = new ParamData();
                    paramData.put("id", id);
                    paramData.put("isActive", false);
                    paramData.put("inactiveTime", date);
                    paramData.put("isDeleted", true);
                    paramDataList.add(paramData);
                }

                dao.batchUpdate(getSqlName("delete"), paramDataList);
            }
        }
    }

    @Override
    public QResultDto findWeightSection(QueryParams params) {
        ParamData pd = this.convertQueryParams(params);
        List<Integer> weightIds = dao.findForList(getSqlName("findByParamListPage"), pd, Integer.class);
        List<WeightSchemaDto> weightSchemaDtoList = new ArrayList<>();
        if (weightIds.size() > 0) {
            for (Integer id : weightIds) {
                weightSchemaDtoList.add(findDtoById(id));
            }
        }
        return new QResultDto(weightSchemaDtoList, pd.getPagination());
    }

    @Override
    public QResultDto getMaxEndPoint(int id) {

        Map<String, BigDecimal> maxEndPoint = (Map<String, BigDecimal>) dao.findForObject(getSqlName("selectMaxEndPoint"), id);

        if (maxEndPoint == null || maxEndPoint.size() == 0) {

            maxEndPoint = new HashedMap();
            maxEndPoint.put("maxEndPoint", new BigDecimal(0));
        }

        QResultDto qResultDto = new QResultDto();

        qResultDto.setData(maxEndPoint);

        return qResultDto;
    }

    /**
     * 检查数据有效性
     *
     * @return
     */
    public boolean checkDataValidate(List<WeightSection> weightSectionList) {

        for (int i = 0; i < weightSectionList.size(); i++) {
            if (weightSectionList.get(i).getStartPoint().doubleValue() >= weightSectionList.get(i).getEndPoint().doubleValue()) {
                return false;
            }
        }

        return true;
    }

    /**
     * 检查记录是否已经存在
     *
     * @return
     */
    @Override
    public boolean isExistedWeightSchema(WeightSchema weightSchema) {
        List<WeightSchema> weightSchemaList = dao.findForList(getSqlName("selectMasterDataByParams"), weightSchema, WeightSchema.class);


        return weightSchemaList != null && weightSchemaList.size() > 0;

    }

    /**
     * 凭借Id查找对应记录
     *
     * @return
     */
    public WeightSchema findById(Integer id) {
        WeightSchema weightSchema = null;
        if (id != null && id.intValue() > 0) {
            weightSchema = (WeightSchema) dao.findForObject(getSqlName("findById"), id);
        }
        return weightSchema;
    }

    /**
     * 瓶ID列表查找对应记录
     *
     * @return
     */
    public List<WeightSchema> findByIds(List<Integer> ids) {
        List<WeightSchema> list = new ArrayList<>();
        if (ids != null && ids.size() > 0) {
            ParamData pd = new ParamData();
            pd.put("ids", ids);
            list = dao.findForList(getSqlName("findByIds"), pd, WeightSchema.class);
        }
        return list;
    }

    /**
     * 凭借ID查找对应计重dto
     *
     * @return
     */
    private WeightSchemaDto findDtoById(Integer id) {
        WeightSchema weightSchema = findById(id);

        if (weightSchema != null && weightSchema.getId().intValue() > 0) {
            WeightSchemaDto weightSchemaDto = new WeightSchemaDto();
            EntityUtils.copyPropertiesIgnoreNull(weightSchema, weightSchemaDto);

            List<WeightSection> weightSectionList = dao.findForList("WeightSectionMapper.selectByRefId", id, WeightSection.class);

            weightSchemaDto.setWeightSectionList(weightSectionList);

            return weightSchemaDto;
        }

        return null;
    }

    /**
     * 根据uid查询可用生效的实体
     *
     * @param uid 主键id
     * @return 查询出来的实体对象
     */
    @Override
    public WeightSchemaDto findActivedByUid(String uid) {

        WeightSchemaDto weightSchemaDto = null;

        WeightSchema weightSchema = (WeightSchema) dao.findForObject(getSqlName("findActivedByUid"), uid);

        if (weightSchema != null && weightSchema.getId().intValue() > 0) {

            weightSchemaDto = findDtoById(weightSchema.getId());
        }

        return weightSchemaDto;
    }

    /**
     * 根据uid查询可用生效的实体
     *
     * @param uid  uid
     * @param time 时间点
     * @return 查询出来的实体对象
     */
    @Override
    public WeightSchemaDto findByUidAndTime(String uid, Date time) {

        WeightSchemaDto weightSchemaDto = null;

        Map<String, Object> map = new HashMap<>();
        map.put("uid", uid);
        map.put("time", time);

        WeightSchema weightSchema = (WeightSchema) dao.findForObject(getSqlName("findByUidAndTime"), map);

        if (weightSchema != null && weightSchema.getId().intValue() > 0) {

            weightSchemaDto = findDtoById(weightSchema.getId());
        }

        return weightSchemaDto;
    }

    /**
     * @return
     */

    @Override
    protected String getMapperNamespace() {
        return "WeightSchemaMapper";
    }
}
